/**
 * 增强的Axios请求配置
 * 包含：超时、重试、请求取消、错误处理
 */
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import config from '../config'

// 请求队列，用于取消
const pendingRequests = new Map()

// Token刷新状态管理
let isRefreshing = false
let refreshSubscribers = []

// 添加刷新请求到队列
function subscribeTokenRefresh(callback) {
  refreshSubscribers.push(callback)
}

// 刷新成功后通知所有等待的请求
function onRefreshed(token) {
  refreshSubscribers.forEach(callback => callback(token))
  refreshSubscribers = []
}

// 生成请求key
function generateRequestKey(config) {
  const { method, url, params, data } = config
  return [method, url, JSON.stringify(params), JSON.stringify(data)].join('&')
}

// 添加请求到队列
function addPendingRequest(config) {
  const requestKey = generateRequestKey(config)
  
  // 如果存在相同的pending请求，取消它
  if (pendingRequests.has(requestKey)) {
    const controller = pendingRequests.get(requestKey)
    controller.abort('取消重复请求')
  }
  
  // 创建新的AbortController
  const controller = new AbortController()
  config.signal = controller.signal
  pendingRequests.set(requestKey, controller)
}

// 移除pending请求
function removePendingRequest(config) {
  const requestKey = generateRequestKey(config)
  if (pendingRequests.has(requestKey)) {
    pendingRequests.delete(requestKey)
  }
}

// 创建axios实例
const request = axios.create({
  baseURL: config.API_BASE_URL,
  timeout: config.API_TIMEOUT || 30000, // 默认30秒
  headers: {
    'Content-Type': 'application/json'
  }
})

/**
 * 重试配置
 */
const retryConfig = {
  retries: 3, // 重试次数
  retryDelay: (retryCount) => {
    // 指数退避：1秒、3秒、5秒
    const delays = [1000, 3000, 5000]
    return delays[retryCount - 1] || 5000
  },
  retryCondition: (error) => {
    // 只对网络错误和5xx错误重试
    return !error.response || (error.response.status >= 500 && error.response.status < 600)
  }
}

/**
 * 请求拦截器
 */
request.interceptors.request.use(
  async (config) => {
    // 添加认证token
    const token = localStorage.getItem('token')
    if (token) {
      // 检查token是否即将过期（5分钟内）
      const willExpireSoon = checkTokenExpiration(token, 5 * 60)
      
      if (willExpireSoon && !isRefreshing && !config.skipTokenCheck) {
        console.log('⚠️ Token即将过期，自动刷新中...')
        await refreshTokenIfNeeded()
      }
      
      config.headers.Authorization = `Bearer ${token}`
    }
    
    // 添加请求ID用于追踪
    config.requestId = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
    
    // 添加到pending队列（可选，根据配置）
    if (!config.skipCancelDuplicate) {
      addPendingRequest(config)
    }
    
    // 初始化重试计数
    config.retryCount = config.retryCount || 0
    
    console.log(`🚀 [${config.requestId}] 请求开始:`, {
      method: config.method?.toUpperCase(),
      url: config.url,
      retry: config.retryCount
    })
    
    return config
  },
  (error) => {
    console.error('❌ 请求拦截器错误:', error)
    return Promise.reject(error)
  }
)

/**
 * 响应拦截器
 */
request.interceptors.response.use(
  (response) => {
    // 移除pending请求
    removePendingRequest(response.config)
    
    console.log(`✅ [${response.config.requestId}] 请求成功:`, {
      status: response.status,
      url: response.config.url
    })
    
    // 返回数据
    return response.data
  },
  async (error) => {
    const originalRequest = error.config
    
    // 请求被取消
    if (axios.isCancel(error)) {
      console.log('⚠️ 请求被取消:', error.message)
      return Promise.reject({ cancelled: true, message: error.message })
    }
    
    // 移除pending请求
    if (originalRequest) {
      removePendingRequest(originalRequest)
    }
    
    // 处理认证错误
    if (error.response?.status === 401) {
      return handleAuthError(error)
    }
    
    // 重试逻辑
    if (originalRequest && shouldRetry(error, originalRequest)) {
      return retryRequest(error, originalRequest)
    }
    
    // 错误处理
    return handleError(error)
  }
)

/**
 * 判断是否应该重试
 */
function shouldRetry(error, config) {
  // 已达到最大重试次数
  if (config.retryCount >= retryConfig.retries) {
    return false
  }
  
  // 检查是否满足重试条件
  return retryConfig.retryCondition(error)
}

/**
 * 重试请求
 */
async function retryRequest(error, config) {
  config.retryCount += 1
  
  const delay = retryConfig.retryDelay(config.retryCount)
  
  console.log(`🔄 [${config.requestId}] 第${config.retryCount}次重试，等待${delay}ms...`)
  
  // 等待指定时间
  await new Promise(resolve => setTimeout(resolve, delay))
  
  // 重新发起请求
  return request(config)
}

/**
 * 处理认证错误
 */
async function handleAuthError(error) {
  const originalRequest = error.config
  
  // 如果是刷新token的请求失败，直接登出
  if (originalRequest.url?.includes('/auth/refresh')) {
    console.log('🔒 Token刷新失败，需要重新登录')
    forceLogout()
    return Promise.reject({
      status: 401,
      message: '登录已过期'
    })
  }
  
  // 避免重复处理同一个请求
  if (originalRequest._retry) {
    console.log('🔒 请求已重试过，直接登出')
    forceLogout()
    return Promise.reject(error)
  }
  
  // 标记请求已重试
  originalRequest._retry = true
  
  // 尝试刷新token
  if (!isRefreshing) {
    isRefreshing = true
    
    try {
      console.log('🔄 尝试刷新token...')
      const { AuthService } = await import('../services/auth')
      const refreshResult = await AuthService.refreshToken()
      
      const newToken = refreshResult.token || localStorage.getItem('token')
      
      if (newToken) {
        isRefreshing = false
        console.log('✅ Token刷新成功，重试原始请求')
        
        // 通知所有等待的请求
        onRefreshed(newToken)
        
        // 重试原始请求
        originalRequest.headers.Authorization = `Bearer ${newToken}`
        return request(originalRequest)
      } else {
        throw new Error('刷新后未获取到新token')
      }
      
    } catch (refreshError) {
      console.error('❌ Token刷新失败:', refreshError)
      isRefreshing = false
      refreshSubscribers = []
      forceLogout()
      return Promise.reject(refreshError)
    }
  } else {
    // 如果正在刷新，将请求加入队列
    console.log('⏳ Token正在刷新中，请求加入队列')
    return new Promise((resolve, reject) => {
      subscribeTokenRefresh((token) => {
        originalRequest.headers.Authorization = `Bearer ${token}`
        resolve(request(originalRequest))
      })
    })
  }
}

/**
 * 统一错误处理
 */
function handleError(error) {
  const config = error.config || {}
  const response = error.response
  
  // 构建错误对象
  const errorObj = {
    requestId: config.requestId,
    status: response?.status,
    message: '请求失败',
    data: response?.data,
    originalError: error
  }
  
  // 根据状态码显示不同错误信息
  if (response) {
    switch (response.status) {
      case 400:
        errorObj.message = response.data?.message || '请求参数错误'
        break
      case 403:
        errorObj.message = '没有权限执行此操作'
        break
      case 404:
        errorObj.message = '请求的资源不存在'
        break
      case 409:
        errorObj.message = response.data?.message || '数据冲突'
        break
      case 422:
        errorObj.message = response.data?.message || '数据验证失败'
        break
      case 500:
        errorObj.message = '服务器内部错误'
        break
      case 502:
        errorObj.message = '网关错误'
        break
      case 503:
        errorObj.message = '服务暂时不可用'
        break
      default:
        errorObj.message = response.data?.message || `请求失败 (${response.status})`
    }
  } else if (error.code === 'ECONNABORTED') {
    errorObj.message = '请求超时，请检查网络连接'
  } else if (error.message === 'Network Error') {
    errorObj.message = '网络连接失败，请检查网络'
  } else {
    errorObj.message = error.message || '未知错误'
  }
  
  console.error(`❌ [${config.requestId}] 请求失败:`, errorObj)
  
  // 如果不是静默请求，显示错误提示
  if (!config.silent) {
    showErrorMessage(errorObj)
  }
  
  return Promise.reject(errorObj)
}

/**
 * 显示错误消息（带重试选项）
 */
function showErrorMessage(error) {
  // 对于某些错误，提供重试选项
  if (error.status >= 500 || error.message.includes('网络') || error.message.includes('超时')) {
    ElMessageBox.confirm(
      `${error.message}。是否重试？`,
      '请求失败',
      {
        confirmButtonText: '重试',
        cancelButtonText: '取消',
        type: 'error'
      }
    ).then(() => {
      // 用户选择重试
      if (error.originalError?.config) {
        const config = error.originalError.config
        config.retryCount = 0 // 重置重试计数
        request(config)
      }
    }).catch(() => {
      // 用户取消
    })
  } else {
    // 普通错误提示
    ElMessage.error(error.message)
  }
}

/**
 * 取消所有pending请求
 */
export function cancelAllRequests(message = '路由切换，取消所有pending请求') {
  console.log(`🛑 取消${pendingRequests.size}个pending请求`)
  
  pendingRequests.forEach((controller) => {
    controller.abort(message)
  })
  
  pendingRequests.clear()
}

/**
 * 取消特定请求
 */
export function cancelRequest(requestKey) {
  if (pendingRequests.has(requestKey)) {
    const controller = pendingRequests.get(requestKey)
    controller.abort('手动取消请求')
    pendingRequests.delete(requestKey)
  }
}

/**
 * 检查token是否即将过期
 * @param {string} token - JWT token
 * @param {number} thresholdSeconds - 过期阈值（秒）
 * @returns {boolean}
 */
function checkTokenExpiration(token, thresholdSeconds) {
  try {
    const parts = token.split('.')
    if (parts.length !== 3) return false
    
    const payload = JSON.parse(atob(parts[1]))
    const now = Math.floor(Date.now() / 1000)
    
    if (payload.exp) {
      const timeUntilExpiry = payload.exp - now
      return timeUntilExpiry > 0 && timeUntilExpiry < thresholdSeconds
    }
  } catch (error) {
    console.error('检查token过期时间失败:', error)
  }
  return false
}

/**
 * 刷新token（防并发）
 */
async function refreshTokenIfNeeded() {
  if (isRefreshing) {
    console.log('⏳ Token正在刷新中，跳过重复刷新')
    return
  }
  
  isRefreshing = true
  try {
    const { AuthService } = await import('../services/auth')
    await AuthService.refreshToken()
    console.log('✅ Token已自动刷新')
  } catch (error) {
    console.error('❌ 自动刷新token失败:', error)
  } finally {
    isRefreshing = false
  }
}

/**
 * 强制登出
 */
function forceLogout() {
  // 清除本地存储
  localStorage.removeItem('token')
  localStorage.removeItem('user_info')
  localStorage.removeItem('auth')
  
  // 显示提示
  ElMessage.warning('登录已过期，请重新登录')
  
  // 延迟跳转到登录页
  setTimeout(() => {
    window.location.href = '/login'
  }, 1500)
}

export default request

